package socket.nio.demo_03;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Set;

public class EchoServer {
    public static final int DEFAULT_PORT = 8080;

    public static void main(String[] args) {
        System.out.println("Listening for connections on port " + DEFAULT_PORT);

        ServerSocketChannel serverChannel;
        Selector selector;
        try {
            serverChannel = ServerSocketChannel.open();
            serverChannel.bind(new InetSocketAddress(DEFAULT_PORT));
            serverChannel.configureBlocking(false);
            selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        while(true) {
            try{
                selector.select();
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }

            Set<SelectionKey> readyKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = readyKeys.iterator();
            String outString = "HelloWorld";
            while(iterator.hasNext()) {
                SelectionKey serverKey = iterator.next();
                iterator.remove();
                try {
                    if(serverKey.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) serverKey.channel();
                        SocketChannel client = server.accept();
                        System.out.println("Accepted connection from " + client);
                        client.configureBlocking(false);
                        SelectionKey clientKey = client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ);
                        ByteBuffer buffer = ByteBuffer.allocate(100);

                        buffer.put(outString.getBytes());
                        clientKey.attach(buffer);
                    }

                    if(serverKey.isReadable()) {
                        SocketChannel client = (SocketChannel) serverKey.channel();
                        ByteBuffer output = (ByteBuffer) serverKey.attachment();
                        int n = client.read(output);
                        if(n > 0) {
                            output.flip();
                            outString = Arrays.toString(output.array());
                            System.out.println(new String(output.array()));
                            output.clear();
                        } else if(n == -1) {
                            // 这不应该发生，除非服务器发生异常
                            break;
                        }
                    }

                    if(serverKey.isWritable()) {
                        SocketChannel client = (SocketChannel) serverKey.channel();
                        ByteBuffer output = (ByteBuffer) serverKey.attachment();
                        if(!output.hasRemaining()) {
                            output.flip();
                        }
                        output.put(outString.getBytes());
                        client.write(output);
                        output.compact();
                    }
                } catch (IOException e) {
                    serverKey.cancel();
                    try {
                        serverKey.channel().close();
                    } catch (IOException e1) {

                    }
                }
            }
        }
    }
}
